package cc.co.cutenimy.java.guicejunit4;

import java.lang.reflect.InvocationTargetException;

import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;

public class GuiceJunit4Runner extends BlockJUnit4ClassRunner {

	public GuiceJunit4Runner(Class<?> klass) throws InitializationError {
		super(klass);
	}

	/**
	 * If the test class is the module, then just use this class to create Guice
	 * instance and then try to find the {@link ModuleBy} annotation to set the
	 * module configuration.
	 */
	@SuppressWarnings("unchecked")
	@Override
	protected Object createTest() throws Exception {
		try {
			// return super.createTest();
			Class<?> javaClass = getTestClass().getJavaClass();
			if (AbstractModule.class.isAssignableFrom(javaClass)) {
				return initializeInjectAndTestInstance(javaClass,
						(Class<? extends AbstractModule>) getTestClass()
								.getJavaClass());
			} else if (javaClass.isAnnotationPresent(ModuleBy.class)) {
				Class<? extends AbstractModule> module = javaClass
						.getAnnotation(ModuleBy.class).value();
				return initializeInjectAndTestInstance(javaClass, module);
			}
			return super.createTest();
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}

	private Object initializeInjectAndTestInstance(Class<?> javaClass,
			Class<? extends AbstractModule> module)
			throws InstantiationException, IllegalAccessException,
			InvocationTargetException, NoSuchMethodException {
		Injector injector = Guice.createInjector(module.getConstructor()
				.newInstance());
		return injector.getInstance(javaClass);
	}

}
